package com.cacho.s2b.lesson.utils;

import com.cacho.s2b.lesson.learn.LearnBase64;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.io.FileUtils;
import org.springframework.util.Assert;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class EncryptHelper {
    private static String IV = "0123456789ABCDEF"; //初始向量 IV 的长度规定为128位16个字节，初始向量通常采用随机生成
    // AES-128-CBC 加解密
    private static Key generateKey(String key){
        try {
            MessageDigest md = MessageDigest.getInstance(Constants.AES);
            byte [] md5 = md.digest(key.getBytes(StandardCharsets.UTF_8));
            return new SecretKeySpec(md5,Constants.AES);
        }catch(Exception ex){
            throw new RuntimeException(ex);
        }
    }
    public static String AesCbcEncrypt (String blankText, String key){
        Assert.notNull(blankText, "blankText must not be null");
        Assert.notNull(key, "key must not be null");
        try {
            IvParameterSpec iv =  new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
            Cipher cipher = Cipher.getInstance(Constants.AES_CBC_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, generateKey(key), iv);
            byte[] encrypted = cipher.doFinal(blankText.getBytes(StandardCharsets.UTF_8));
            return LearnBase64.encode(encrypted);

        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }
    public static String AesCbcDecrypt (String decryptText, String key){
        Assert.notNull(decryptText, "decryptText must not be null");
        Assert.notNull(key, "key must not be null");
        try {
            IvParameterSpec iv =  new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
            Cipher cipher = Cipher.getInstance(Constants.AES_CBC_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, generateKey(key), iv);
            byte[] decrypted  = cipher.doFinal(Base64.getDecoder().decode(decryptText));
            return LearnBase64.decode(decrypted);

        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }
    public static String encode (File file){
        try {
            byte[] fileEncodeBytes = Base64.getEncoder().encode(FileUtils.readFileToByteArray(file));
            return new String(fileEncodeBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new EncryptException(e);
        }
    }
    public PrivateKey StringToPrivateKey(String keyString) {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(DatatypeConverter.parseBase64Binary(keyString));
        try {
            KeyFactory factory = KeyFactory.getInstance(Constants.RSA);
            return factory.generatePrivate(spec);
        } catch (InvalidKeySpecException | NoSuchAlgorithmException ex){
            throw new RuntimeException(ex.getMessage(),ex);
        }
    }

    public PublicKey StringToPublicKey(String keyString) {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(keyString));
        try {
            KeyFactory factory = KeyFactory.getInstance(Constants.RSA);
            return factory.generatePublic(spec);
        } catch (InvalidKeySpecException | NoSuchAlgorithmException ex){
            throw new RuntimeException(ex.getMessage(),ex);
        }
    }
    public static void main(String[] args){
        System.out.println("加密后：" + AesCbcEncrypt("Iamview1234#","CACHO"));
        System.out.println("解密后：" + AesCbcDecrypt("tM/s027urMJIEyQjGiijKA==","CACHO"));
        if (args.length < 1){
            System.err.println("无效的文件路径，格式应该为：");
            System.exit(-1);
        }
        String filePath = args[0];
        String output = encode(new File(filePath));
        System.out.printf("Base64加密文件%s为String：\n%s%n",filePath,output);
    }
}
